﻿///<reference path="~/scripts/Awesome.js" />

var AwesomeTesting = {
    Tests: [],
    FormStates: [],
    TestUI: new Div().Position("fixed").Y(0).X(0).Width("100%").Style(Style.ZIndex, "1000000"),
    FormStateUI: new Div().Position("fixed").X(0).Style(Style.Bottom, "0px").Style(Style.Border, "1px solid #000000").BackgroundColor(Colors.White).Width("100%").Style(Style.Padding, "4px").Style(Style.ZIndex, "1000000")
};

$_at = AwesomeTesting.Tests;
$_afs = AwesomeTesting.FormStates;
$_tui = AwesomeTesting.TestUI;
$_fsui = AwesomeTesting.FormStateUI;

function UnitTest(name, setup, funcArray, teardown) {
    this.SetUp = setup;
    this.Tests = [];
    var l = funcArray.length;
    for (var i = 0; i < l; i++) {
        this.Tests.Add(new UnitTestFunction(funcArray[i]));
    }

    this.TearDown = teardown;
    this.Name = name;
    $_at.Add(this);
}

function UnitTestFunction(func) {
    this.Function = func;
    this.Row = null;
    this.Result = new UnitTestResult();
    this.Enabled = true;
    this.Name = AwesomeTesting.FindFunctionName(func);
    this.TestCount = 0;
    this.TestDelegate = new Delegate(this.HandleAsync, this);
}

UnitTestFunction.prototype.Run = function () {
    if (this.Enabled) {
        if (this.Function.IsAsync) {
            this.TestCount = 0;
            this.Row.Cells[2].BackgroundColor(Colors.White)
            this.Row.Cells[2].Text("Running...");
            this.HandleAsync();
            return;
        }
        else {
            try {
                this.Function();
                this.Result.Result = true;
            }
            catch (e) {
                this.Result.Result = false;
                this.Result.Message = e;
            }
        }
    }
    else {
        this.Result.Result = null;
    }

    if (this.Result.Result == null) {
        this.Row.Cells[2].Text("None").BackgroundColor(Colors.White);
        this.Row.Cells[3].Text("");
    }
    else if (this.Result.Result == true) {
        this.Row.Cells[2].Text("Passed").BackgroundColor(Colors.GreenYellow);
        this.Row.Cells[3].Text("");
    }
    else {
        this.Row.Cells[2].Text("Failed").BackgroundColor(Colors.Red);
        this.Row.Cells[3].Text(this.Result.Message);
    }

}

UnitTestFunction.prototype.HandleAsync = function () {
    this.TestCount++;
    try {
        this.Function();
        this.Result.Result = true;
        this.TestCount = 5;
    }
    catch (e) {
        this.Result.Result = false;
        this.Result.Message = e;
        if (this.TestCount < 5) {
            Timer.Delay(this.Function.Delay, this.TestDelegate);
        }
    }

    if (this.TestCount == 5) {
        if (this.Result.Result == null) {
            this.Row.Cells[2].Text("None").BackgroundColor(Colors.White);
            this.Row.Cells[3].Text("");
        }
        else if (this.Result.Result == true) {
            this.Row.Cells[2].Text("Passed").BackgroundColor(Colors.GreenYellow);
            this.Row.Cells[3].Text("");
        }
        else {
            this.Row.Cells[2].Text("Failed").BackgroundColor(Colors.Red);
            this.Row.Cells[3].Text(this.Result.Message);
        }
    }
}

function UnitTestResult(result, message) {
    this.Result = result;
    this.Message = message;
}

AwesomeTesting.FindFunctionName = function (func) {
    var f = func.toString();
    f = f.Substring(9, f.IndexOf("("));
    return f.length == 0 ? "Unknown function name" : f;
}

AwesomeTesting.EnableTest = function (test, checkBox) {
    test.Enabled = checkBox.Checked();
};

AwesomeTesting.CreateTestEnvironment = function () {
    var a = AwesomeTesting.Tests;
    if (a.length > 0) {
        var t = new Table();
        t.Width("100%").CellPadding(0).CellSpacing(1).Style("border", "1px solid #000000").BackgroundColor(Colors.LightGrey);

        var l = a.length;
        var r, c, v, x;

        r = new Row();
        r.Cells.Add(new Cell());
        r.Cells.Add(new Cell().Text("Function"));
        r.Cells.Add(new Cell().Text("Result"));
        r.Cells.Add(new Cell().Text("Message"));
        t.Rows.Add(r);
        for (var i = 0; i < l; i++) {
            r = new Row().BackgroundColor(Colors.Bisque);
            v = a[i];
            c = new Cell().Text(v.Name).Bold(true).ColumnSpan(4);
            x = new Button().Text("Run");
            x.OnClick.Add(new Delegate(v.Run, v));
            c.InsertElement(0, x);
            r.Cells.Add(c);
            t.Rows.Add(r);
            v.RowStart = r;
            var b = v.Tests;
            var m = b.length;
            for (var j = 0; j < m; j++) {
                r = new Row().BackgroundColor(Colors.White);
                c = new Cell();
                v = b[j];
                v.Enabled = true;
                v.Row = r;
                x = new CheckBox().Checked(true);
                x.OnCheckChanged.Add(new Delegate(UnitTest.EnableTest, null, v, x));
                c.AddElement(x);
                c.AttributeWidth(25);
                r.Cells.Add(c);
                r.Cells.Add(new Cell().Text(v.Name).AttributeWidth(150));
                r.Cells.Add(new Cell().Text("None").AttributeWidth(100));
                r.Cells.Add(new Cell());
                t.Rows.Add(r);
            }
        }

        var d = $_tui.Icon = new Div().Style(Style.ZIndex, "1000001");
        d.OnMouseOver.Add(AwesomeTesting.HideIcon);
        d.OnMouseMove.Add(AwesomeTesting.HideIcon);
        d.OnMouseOut.Add(AwesomeTesting.HideIcon);
        d.Text("▲").Style(Style.TextAlign, "center").Cursor(Cursor.Pointer).Style(Style.Border, "1px solid #000000").Style(Style.BorderTop, "none").Position("fixed").Width(100).BackgroundColor(Colors.White).ToolTip("Click to toggle unit test display");
        d.OnClick.Add(AwesomeTesting.ToggleUnitTestDisplay);

        Page.InsertElement(0, d);
        $_tui.AddElement(t);
        Page.InsertElement(0, $_tui);

        d.X(t.LayoutWidth() / 2 - $_tui.Icon.LayoutWidth() / 2).Y($_tui.Y() + $_tui.LayoutHeight() - 1);

        var c = Client.Cookies["$ui_test_toggle"];
        if (c) {
            if (c.Value().ToBoolean()) {
                AwesomeTesting.ToggleUnitTestDisplay();
            }
        }
    }

    var w = Client.Cookies["$formstate_list"];
    var fs;
    if (w) {
        w = w.Value();
        var m = w.length;
        for (var i = 0; i < m; i++) {
            var c = Client.Cookies[w[i]];
            if (c) {
                fs = c.Value();
                fs.InputStates = Dictionary.FromObject(fs.InputStates);
                AwesomeTesting.FormStates.Add(fs);
            }
        }
    }

    var c = new DropDownList("$CmbFormStateList").Width(150);
    var b = new Button().Text("Load State");

    b.OnClick.Add(FormState.LoadState);
    $_fsui.AddElement(b);
    $_fsui.AddElement(c);

    b = new Button().Text("Delete State");
    b.OnClick.Add(FormState.DeleteCurrent);
    $_fsui.AddElement(b);
    b = new Button().Text("Save Existing");
    b.OnClick.Add(FormState.SaveExisting);
    $_fsui.AddElement(b);
    b = new Button("").Text("Create New");
    b.OnClick.Add(FormState.CreateNew);
    $_fsui.AddElement(b);
    var txt = new TextBox("$TxtFormStateName").Text("Form state #" + (AwesomeTesting.FormStates.length + 1));
    $_fsui.AddElement(txt);

    var d = $_fsui.Icon = new Div().Style(Style.ZIndex, "1000001");
    d.OnMouseOver.Add(AwesomeTesting.HideIcon);
    d.OnMouseMove.Add(AwesomeTesting.HideIcon);
    d.OnMouseOut.Add(AwesomeTesting.HideIcon);
    d.Text("▼").Style(Style.TextAlign, "center").Cursor(Cursor.Pointer).Style(Style.Border, "1px solid #000000").Style(Style.BorderBottom, "none").Position("fixed").Width(100).BackgroundColor(Colors.White).ToolTip("Click to toggle form state display");
    d.OnClick.Add(AwesomeTesting.ToggleFormStateDisplay);

    Page.AddElement($_fsui);
    Page.AddElement(d);

    d.X($_fsui.LayoutWidth() / 2 - d.LayoutWidth() / 2).Style(Style.Bottom, ($_fsui.LayoutHeight() - 1) + "px");


    var c = Client.Cookies["$ui_formstate_toggle"];
    if (c) {
        if (c.Value().ToBoolean()) {
            AwesomeTesting.ToggleFormStateDisplay();
        }
    }

    FormState.UpdateFormStates();
}


AwesomeTesting.ShowIcon = function (e) {
    e.Sender.Collapsed(false);
}

AwesomeTesting.HideIcon = function (e) {
    if (Keyboard.ShiftKey) {
        e.Sender.Collapsed(true)
    }
}

AwesomeTesting.ToggleUnitTestDisplay = function () {
    $_tui.Collapsed(!$_tui.Collapsed());
    $_tui.Icon.Text($_tui.Collapsed() ? "▼" : "▲");
    $_tui.Icon.Y($_tui.Y() + $_tui.LayoutHeight() - 1);

    var c = Client.Cookies["$ui_test_toggle"];
    if (!c) {
        c = new Cookie("$ui_test_toggle");
        Client.Cookies.Add(c);
    }

    c.Value(AwesomeTesting.TestUI.Collapsed());
    c.Expires(DateTime.Now().Add(new TimeSpan(1000, 0)));
}

UnitTest.prototype.Run = function () {
    var a = this.Tests;
    var l = a.length;
    var rs = [];
    var r, v, async;
    if (this.SetUp) {
        try {
            this.SetUp();
        }
        catch (e) {
            for (var i = 0; i < l; i++) {
                a[i].Row.Cells[2].Text("Error").BackgroundColor(Colors.Yellow);
                a[i].Row.Cells[3].Text("Error occurred during set up: " + e);
            }

            return;
        }
    }

    for (var i = 0; i < l; i++) {
        a[i].Run();
    }

    if (this.TearDown) {
        this.TearDown();
    }
}

var Assert = {};
Assert.IsTrue = function (result, message) {
    if (result !== true) {
        throw (message || "Result was not true.");
    }
}

Assert.IsFalse = function(result, message) {
    if (result !== false) {
        throw (message || "Result was not false.");
    }
}

Assert.AreValueEqual = function (value1, value2, message) {
    if (value1 != value2) {
        throw (message || "Result was not value equal.");
    }
}

Assert.AreReferenceEqual = function(ref1, ref2, message) {
    if (ref1 !== ref2) {
        throw (message || "Result was not reference equal.");
    }
}

Assert.IsNotNullOrUndefined = function (value, message) {
    if (value === null) {
        throw (message || "Result was null.");
    }
    if (value === undefined) {
        throw (message || "Result was undefined.");
    }
}

Assert.IsNullOrUndefined = function(value, message) {
    if (value !== null || value !== undefined) {
        throw (message || "Result was not null nor undefined.");
    }
}

Assert.IsOfType = function(object, type, message) {
    if (object.Type != type) {
        throw (message || "Object not of specified type.");
    }
}

function AsyncFunction(func, delay) {
    func.IsAsync = true;
    func.Delay = delay;
    func.Executed = false;
    return func;
}

AwesomeTesting.FormStates = [];

function FormState(name) {
    this.InputStates = new Dictionary();
    this.Name = name;

    var a = document.forms[0].elements;
    var l = a.length;
    var v;
    for (var i = 0; i < l; i++) {
        v = a[i];
        if (v.id != "__VIEWSTATE" && v.Type != Type.Button) {
            this.InputStates.Add(v.id, v.Value());
        }
    }
}

AwesomeTesting.ToggleFormStateDisplay = function () {
    $_fsui.Collapsed(!$_fsui.Collapsed());
    $_fsui.Icon.Text($_fsui.Collapsed() ? "▲" : "▼");
    if ($_fsui.Collapsed()) {
        $_fsui.Icon.Style(Style.Bottom, "0px");
    }
    else {
        $_fsui.Icon.Style(Style.Bottom, ($_fsui.LayoutHeight() - 1) + "px");
    }

    var c = Client.Cookies["$ui_formstate_toggle"];
    if (!c) {
        c = new Cookie("$ui_formstate_toggle");
        Client.Cookies.Add(c);
    }

    c.Value(AwesomeTesting.FormStateUI.Collapsed());
    c.Expires(DateTime.Now().Add(new TimeSpan(1000, 0)));
}

FormState.CreateNew = function () {
    var fs = new FormState($TextBox("$TxtFormStateName").Text());
    AwesomeTesting.FormStates.Add(fs);
    $TextBox("$TxtFormStateName").Text("Form state #" + (AwesomeTesting.FormStates.length + 1));
    Client.Cookies.Add(new JSONCookie("$fs_" + fs.Name, fs, new DateTime(2038, 1, 1)));
    FormState.UpdateFormStates();
    FormState.SaveCurrentStates();
}

FormState.SaveExisting = function () {
    var c = $DropDownList("$CmbFormStateList");
    if (c.SelectedIndex() == -1) { return; }

    var fso = c.SelectedOption().Tag;
    var fs = new FormState(fso.Name);
    AwesomeTesting.FormStates.Add(fs);
    AwesomeTesting.FormStates.Swap(fs, fso);
    AwesomeTesting.FormStates.Remove(fso);
    c.SelectedOption().Tag = fs;
    Client.Cookies["$fs_" + fs.Name].Value(fs);
}

FormState.DeleteCurrent = function () {
    var c = $DropDownList("$CmbFormStateList");
    if (c.SelectedIndex() == -1) { return; }

    var fso = c.SelectedOption().Tag;
    AwesomeTesting.FormStates.Remove(fso);
    c.Options.Remove(c.SelectedOption());
    Client.Cookies.Remove(Client.Cookies["$fs_" + fso.Name]);
}

FormState.SaveCurrentStates = function () {
    var c = Client.Cookies["$formstate_list"];
    if (!c) {
        c = new JSONCookie("$formstate_list", []);
        Client.Cookies.Add(c);
    }

    var a = [];
    var b = AwesomeTesting.FormStates;
    var l = b.length;
    var v;
    for (var i = 0; i < l; i++) {
        a.Add("$fs_" + b[i].Name);
    }

    c.Value(a);
    c.Expires(DateTime.Now().Add(new TimeSpan(1000, 0)));
}

FormState.UpdateFormStates = function () {
    var c = $DropDownList("$CmbFormStateList");
    c.Options.BeginUpdate();
    c.Options.Clear();
    var a = AwesomeTesting.FormStates;
    var l = a.length;
    var o, v;
    for (var i = 0; i < l; i++) {
        v = a[i];
        o = new Option(v.Name);
        o.Tag = v;
        c.Options.Add(o);
    }

    c.Options.EndUpdate();
}

FormState.LoadState = function () {
    var c = $DropDownList("$CmbFormStateList");
    if (c.SelectedIndex() < 0) { return; }
    var vs = c.SelectedOption().Tag.InputStates;
    var v;
    vs.ForEach(function (i) {
        v = $Input(i.Key);
        if (v) {
            v.Value(i.Value);
        }
    });
}
Page.OnLoad.Add(AwesomeTesting.CreateTestEnvironment);